using System;
using System.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Web;
using NWrapper.Config;

namespace NWrapper.Logging
{
	/// <summary>
	/// A proxy logger.
	/// </summary>
	public sealed class LoggerProxy : ILogger, IDisposable
	{
		private LoggerType _type;
		private ILogger _logger;
		private bool _disposed = false;

		#region Constructors
		/// <summary>
		/// The constructor will initialize the proxy using the given logger type.
		/// </summary>
		/// <param name="type">The type of logger this proxy will use.</param>
		public LoggerProxy(LoggerType type)
		{
			_type = type;
			Initialize();
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the underlying logger type used by this proxy. Read-only.
		/// </summary>
		public LoggerType LoggerType
		{
			get { return _type; }
		}
		#endregion

		#region ILogger Members
		/// <summary>
		/// Initializes the proxy by creating the underlying logger implementation.
		/// The underlying logger type is provided with the constructor method.
		/// </summary>
		/// <remarks>
		/// Repeated calls to this method will dispose the existing underlying
		/// logger implementation before re-creating it. As a result, this method
		/// can be used to refresh the underlying logger.
		/// </remarks>
		public void Initialize()
		{
			DisposeLogger();

			string assemblyName;
			string className;

			switch (_type)
			{
				case LoggerType.None:
					assemblyName = "NWrapper";
					className = "NWrapper.Logging.NullLogger";
					break;
				case LoggerType.Custom:
					throw new NotImplementedException("LoggerType.Custom not yet implemented");
				case LoggerType.Log4Net:
					assemblyName = "NWrapper.Logging.Log4Net";
					className = "NWrapper.Logging.Log4Net.Log4NetLogger";
					break;
				case LoggerType.NLog:
					assemblyName = "NWrapper.Logging.NLog";
					className = "NWrapper.Logging.NLog.NLogLogger";
					break;
				default:
					throw new ConfigurationErrorsException("Specified logger type in configuration is unknown or invalid");
			}

			_logger = ReflectionHelper.GetObject<ILogger>(assemblyName, className);
			_logger.Initialize();
		}
		/// <summary>
		/// Logs a message at the debug level.
		/// </summary>
		/// <param name="message">The message to log.</param>
		public void Debug(String message)
		{
			_logger.Debug(message);
		}
		/// <summary>
		/// Logs a message at the debug level.
		/// </summary>
		/// <param name="message">The message (containing format items) to log.</param>
		/// <param name="args">The format arguments.</param>
		public void Debug(String message, params object[] args)
		{
			_logger.Debug(message, args);
		}
		/// <summary>
		/// Returns true if logging at the debug level is enabled, false otherwise.
		/// </summary>
		public bool IsDebugEnabled
		{
			get { return _logger.IsDebugEnabled; }
		}

		/// <summary>
		/// Logs a message at the info level.
		/// </summary>
		/// <param name="message">The message to log.</param>
		public void Info(String message)
		{
			_logger.Info(message);
		}
		/// <summary>
		/// Logs a message at the info level.
		/// </summary>
		/// <param name="message">The message (containing format items) to log.</param>
		/// <param name="args">The format arguments.</param>
		public void Info(String message, params object[] args)
		{
			_logger.Info(message, args);
		}
		/// <summary>
		/// Returns true if logging at the info level is enabled, false otherwise.
		/// </summary>
		public bool IsInfoEnabled
		{
			get { return _logger.IsInfoEnabled; }
		}

		/// <summary>
		/// Logs a message at the warning level.
		/// </summary>
		/// <param name="message">The message to log.</param>
		public void Warning(String message)
		{
			_logger.Warning(message);
		}
		/// <summary>
		/// Logs a message at the warning level.
		/// </summary>
		/// <param name="message">The message (containing format items) to log.</param>
		/// <param name="args">The format arguments.</param>
		public void Warning(String message, params object[] args)
		{
			_logger.Warning(message, args);
		}
		/// <summary>
		/// Returns true if logging at the warning level is enabled, false otherwise.
		/// </summary>
		public bool IsWarningEnabled
		{
			get { return _logger.IsWarningEnabled; }
		}

		/// <summary>
		/// Logs a message at the error level.
		/// </summary>
		/// <param name="message">The message to log.</param>
		public void Error(String message)
		{
			_logger.Error(message);
		}
		/// <summary>
		/// Logs a message at the error level.
		/// </summary>
		/// <param name="message">The message (containing format items) to log.</param>
		/// <param name="args">The format arguments.</param>
		public void Error(String message, params object[] args)
		{
			_logger.Error(message, args);
		}
		/// <summary>
		/// Returns true if logging at the error level is enabled, false otherwise.
		/// </summary>
		public bool IsErrorEnabled
		{
			get { return _logger.IsErrorEnabled; }
		}
		#endregion

		#region IDisposable Members
		/// <summary>
		/// Disposes the proxy and any underlying cache implementations.
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}
		/// <summary>
		/// Manages the disposal of the proxy and underlying cache.
		/// </summary>
		private void Dispose(bool disposing)
		{
			if (_disposed)
				return;

			if (disposing)
			{
				DisposeLogger();
			}

			_disposed = true;
		}
		/// <summary>
		/// Disposes the underlying cache implementation.
		/// </summary>
		private void DisposeLogger()
		{
			if (_logger != null && _logger is IDisposable)
			{
				((IDisposable)_logger).Dispose();
			}
			_logger = null;
		}
		#endregion
	}
}
